﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BasePlatformNet
{
	class LEDPacket
	{
        public const int SHOW_DATA_LENGTH = 1459;   // 显示数据包有效数据长度
		public static int TYPE_FRAME = 0;			// 帧包
		public static int TYPE_DISP_CONFIG = 1;		// 显示设置包
		public static int TYPE_DISP_DATA = 2;		// 显示数据包
		public static int TYPE_CONM_COMMAND = 3;	// 通信命令包
		public static int TYPE_CONM_REPLY = 4;		// 通信应答包
		public static int TYPE_CONM_IDLE = 5;		// 空闲包

		private const int m = 1440;					// 显示数据包有效数据长度 m = 1440

		public byte[] grapRaw;						// 数据包的原始字节流

		public DateTime grapTime;					// 抓取时间

		public const int headLength = 28;			// 报头长度 - 自定义基于UDP的协议, 以 IP 包为准

		public int packetType = -1;					// 包类型

		public byte version;						// 协议版本

		#region 帧包有效数据

		public int view_width = 0;		// 显示宽度=（像素宽度+8）*3
		public int view_height = 0;		// 显示高度=像素高度

		#endregion

		#region 显示数据包有效数据

		public int start_h = 0;			// 显示地址 - 行
		public int start_l = 0;			// 显示地址 - 列
		public int h_size = 0;			// 显示长度

		public int pos_debug = 0;

		#endregion

		#region 显示设置包有效数据

		public byte[] stateBytes;

		#endregion

		#region 通信命令包、通信应答包有效数据

		// 通信命令包有效数据
		public int targetSubCtrlDepth = 0;		// 目标分控级联深度
		public int targetEquipmentDepth = 0;	// 目标附属设备级联深度

		// 通信应答包有效数据
		public int subCtrlDepth = 0;			// 分控级联深度		- 56 字节
		public int equipmentDepth = 0;			// 附属设备级联深度	- 54 字节
		public int subCtrlDepth2 = 0;			// 分控级联深度		- 61 字节
		public int equipmentDepth2 = 0;			// 附属设备级联深度	- 59 字节
		public string firmwareVersion = "";		// 固件版本
		public byte[] replyData = null;			// 应答数据
        public int subType = 0;                 // 分控类型

		// 公共数据
		public int cmdPacketID = -1;				// 通信包序号
		public long cmdAddress = 0;				// 命令地址
		public byte cmdType = 0x0;				// 命令类型

		#endregion

		// 初始化
		public LEDPacket(byte[] raw)
		{
			grapRaw = raw;
			grapTime = DateTime.Now;

			this.analyzePacket(raw);
		}

		// 解析包结构
		public void analyzePacket(byte[] raw)
		{
			// 无效数据包抛错
			if (raw == null || raw.Length < 13)
			{
				throw new ArgumentException();
			}

			if (grapRaw == null)
			{
				grapRaw = raw;
			}

			// 解析协议版本 - HeadLength截取到协议版本0x81
			version = grapRaw[headLength + 0];

			// 解析数据包类型
			if (grapRaw[headLength + 1].Equals(0xFA) && grapRaw[headLength + 2].Equals(0x01))
			{
				packetType = TYPE_FRAME;		// 帧包
			}
			else if (grapRaw[headLength + 1].Equals(0xF0) && grapRaw[headLength + 2].Equals(0x01))
			{
				packetType = TYPE_DISP_CONFIG;	// 显示设置包
			}
			else if (grapRaw[headLength + 1].Equals(0xF5) && grapRaw[headLength + 2].Equals(0x01))
			{
				packetType = TYPE_DISP_DATA;	// 显示数据包
			}
			else if (grapRaw[headLength + 1].Equals(0xC5) && grapRaw[headLength + 2].Equals(0x01))
			{
				packetType = TYPE_CONM_COMMAND;	// 通信命令包
			}
			else if (grapRaw[headLength + 1].Equals(0xC0) && grapRaw[headLength + 2].Equals(0x01))
			{
				packetType = TYPE_CONM_REPLY;	// 通信应答包
			}
			else if (grapRaw[headLength + 1].Equals(0xED) && grapRaw[headLength + 2].Equals(0x01))
			{
				packetType = TYPE_CONM_IDLE;	// 空闲包
			}

			// 解析 帧包 有效数据
			if (packetType == TYPE_FRAME)
			{
				view_width = grapRaw[headLength + 13] & 0xFF;
				view_width |= ((grapRaw[headLength + 14] << 8) & 0xFF00);
				view_width = view_width / 3;	// 显示宽度=（像素宽度+8）*3

				view_height = grapRaw[headLength + 15] & 0xFF;
				view_height |= ((grapRaw[headLength + 16] << 8) & 0xFF00);
			}

			// 解析 显示数据包 有效数据
			if (packetType == TYPE_DISP_DATA)
			{
				// 显示地址 - 行
				start_h = grapRaw[headLength + 8];
				start_h = start_h << 8;
				start_h = start_h + grapRaw[headLength + 7];

				// 显示地址 - 列
				start_l = grapRaw[headLength + 10];
				start_l = start_l << 8;
				start_l = start_l + grapRaw[headLength + 9];

				// 显示长度
				h_size = grapRaw[headLength + 12];
				h_size = h_size << 8;
				h_size = h_size + grapRaw[headLength + 11];
			}

			// 解析 显示设置包 有效数据
			if (packetType == TYPE_DISP_CONFIG)
			{
				if (stateBytes == null)
					stateBytes = new byte[LEDState.stateLength];

				Array.Copy(grapRaw, headLength + 13, stateBytes, 0, LEDState.stateLength);
			}

			// 解析 通信命令包 有效数据
			if (packetType == TYPE_CONM_COMMAND)
			{
				// if(字节58 bit0=0)
				targetSubCtrlDepth = grapRaw[headLength + 8];				// 目标 "分控" 级联深度

				cmdPacketID = grapRaw[headLength + 13] & 0xFF;
				cmdPacketID |= ((grapRaw[headLength + 14] << 8) & 0xFF00);	// 随机的通讯包编号

				cmdType = grapRaw[headLength + 15];							// 命令类型

				cmdAddress = ((long)grapRaw[headLength + 17] & 0xFF);		// 通信命令包有效数据：命令地址
				cmdAddress |= ((long)(grapRaw[headLength + 18] << 8) & 0xFF00);
				cmdAddress |= ((long)(grapRaw[headLength + 19] << 16) & 0xFF0000);
				cmdAddress |= ((long)(grapRaw[headLength + 20] << 24) & 0xFF000000);
			}

			// 解析 通信应答包 有效数据
			if (packetType == TYPE_CONM_REPLY)
			{
				equipmentDepth = grapRaw[headLength + 3];					// 当前 "附属设备"	级联深度 - 54字节
				subCtrlDepth = grapRaw[headLength + 5];						// 当前 "分控"	级联深度 - 56字节
				subCtrlDepth2 = grapRaw[headLength + 8];					// 当前 "分控"	级联深度 - 59字节
				equipmentDepth2 = grapRaw[headLength + 10];					// 当前 "附属设备"	级联深度 - 61字节

				cmdPacketID = grapRaw[headLength + 13] & 0xFF;
				cmdPacketID |= ((grapRaw[headLength + 14] << 8) & 0xFF00);	// 随机的通讯包编号

				cmdType = grapRaw[headLength + 15];							// 命令类型

				int startIndex = 0x000040 + 21;								// 通信应答包 0x40~0x46 区段数据
				System.Text.ASCIIEncoding asciiEncoding = new System.Text.ASCIIEncoding();

				byte[] byteArray = new byte[] { (byte)grapRaw[headLength + startIndex + 0] };
				string funcType = asciiEncoding.GetString(byteArray);			// 系统功能分类
				byteArray = new byte[] { (byte)grapRaw[headLength + startIndex + 1] };
				string subFuncType = asciiEncoding.GetString(byteArray);		// 系统功能子类
				int solutionMainType = grapRaw[headLength + startIndex + 2];	// 解决方案主类型
				int solutionSubType = grapRaw[headLength + startIndex + 3];		// 解决方案子类型
				byteArray = new byte[] { (byte)grapRaw[headLength + startIndex + 4] };
				string appType = asciiEncoding.GetString(byteArray);			// 应用类型
				int projMainType = grapRaw[headLength + startIndex + 5];		// 逻辑工程主版本
				int projSubType = grapRaw[headLength + startIndex + 6];			// 逻辑工程子版本
				int projMiniType = grapRaw[headLength + startIndex + 7];		// 逻辑工程 mini 版本
                subType = grapRaw[headLength + startIndex + 8];                 // 分控类型

				// 固件版本, 如 SL908_G03_XX
				firmwareVersion = funcType + subFuncType + solutionMainType + solutionSubType.ToString().PadLeft(2, '0')
					 + "_" + appType + projMainType.ToString().PadLeft(2, '0') + "_X" + projSubType.ToString().PadLeft(2, '0');

				if (projMiniType != 0)
				{
					firmwareVersion += ("_" + projMiniType);
				}

				// 负载数据
				if (packetType == TYPE_CONM_REPLY)
				{
					replyData = new byte[256];
					Array.Copy(grapRaw, headLength + 21, replyData, 0, 256);
				}
			}
		}

		// 填充显示数据
		public void fillDispData(ref byte[] buffer, int width, int height, Color fillColor)
		{
			int pos_h = start_h;
			int pos_l = start_l;
			int pos = pos_h * h_size + pos_l;
			int pos_reverse = view_width * view_height - pos;

			for (int k = headLength + 13; k < grapRaw.Length; k += 3)
			{
				buffer[pos + k - 13 - headLength] = grapRaw[k + 2];
				buffer[pos + k - 13 - headLength + 1] = grapRaw[k + 1];
				buffer[pos + k - 13 - headLength + 2] = grapRaw[k];
			}
		}
	}
}
